import { app, BrowserWindow, Menu, protocol, net } from 'electron'
import fs from 'fs'
import path from 'path'
import { electronApp, optimizer, is, platform } from '@electron-toolkit/utils'
import { pathToFileURL } from 'url'
import icon from '../../resources/icons/icon.png?asset'
import { getVideoFromPath } from './utils'
import ipc from './ipc'
import { IpcEvents } from '../common/ipcEvents'
import DecryptTransform from './DecryptTransform'

let mainWindow: BrowserWindow | null

function createWindow(): void {
  mainWindow = new BrowserWindow({
    title: 'RpaPlayer',
    width: 860,
    height: 520,
    minWidth: 640,
    minHeight: 420,
    show: false,
    frame: platform.isLinux,
    titleBarStyle: 'hiddenInset',
    trafficLightPosition: {
      x: 8,
      y: 8
    },
    autoHideMenuBar: true,
    ...(process.platform === 'linux' ? { icon } : {}),
    webPreferences: {
      preload: path.join(__dirname, '../preload/index.js'),
      webSecurity: false,
      sandbox: false
    }
  })

  mainWindow.on('ready-to-show', () => {
    mainWindow?.show()
  })

  mainWindow.webContents.on('dom-ready', () => {
    playVideo()
  })

  mainWindow.on('minimize', () => {
    sendIPC(IpcEvents.EV_PAUSE)
  })

  mainWindow.on('maximize', () => {
    sendIPC(IpcEvents.WIN_MAX_REPLY, true)
  })

  mainWindow.on('unmaximize', () => {
    sendIPC(IpcEvents.WIN_MAX_REPLY, false)
  })

  mainWindow.on('close', () => {
    if (mainWindow) mainWindow = null
  })

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'))
  }
}

function sendIPC(channel: IpcEvents, ...args): void {
  mainWindow?.webContents.send(channel, ...args)
}

function initApp(): void {
  // Make this app a single instance app.
  const lock = app.requestSingleInstanceLock()

  if (!lock) {
    app.quit()
  } else {
    app.on('second-instance', (_, argv: string[]) => {
      // log.info('second-instance:' + JSON.stringify(argv))
      if (mainWindow) {
        if (mainWindow.isMinimized()) mainWindow.restore()
        mainWindow.focus()
        playVideo(argv)
      }
    })

    app.whenReady().then(() => {
      // Set app user model id for windows
      electronApp.setAppUserModelId('rpa-player')

      // Default open or close DevTools by F12 in development
      // and ignore CommandOrControl + R in production.
      // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
      app.on('browser-window-created', (_, window) => {
        optimizer.watchWindowShortcuts(window)
      })

      if (platform.isMacOS) {
        Menu.setApplicationMenu(Menu.buildFromTemplate([]))
      }

      optimizer.registerFramelessWindowIpc()

      ipc.register()

      createWindow()

      app.on('activate', function () {
        if (BrowserWindow.getAllWindows().length === 0) createWindow()
      })
    })

    app.whenReady().then(() => {
      // 注册自定义协议
      protocol.handle('atom', (request) => {
        const filePath = path.resolve(decodeURIComponent(request.url.substr(8)))
        const ext = path.extname(filePath).toLowerCase().slice(1)
        const mime = getMimeType(ext) || 'application/octet-stream'

        // 处理文件不存在的情况
        if (!fs.existsSync(filePath)) {
          return new Response('Not Found', { status: 404 })
        }

        if (mime.startsWith('image')) {
          // 图片
          return net.fetch(pathToFileURL(filePath).toString())
        }

        // 获取文件信息
        const stats = fs.statSync(filePath)
        const fileSize = stats.size

        // 解析 Range 请求头
        const rangeHeader = request.headers.get('range') || ''

        const isRangeRequest = !!rangeHeader

        // 处理范围请求
        if (isRangeRequest) {
          const range = parseRangeHeader(rangeHeader, fileSize)
          if (!range) {
            return new Response('Range Not Satisfiable', {
              status: 416,
              headers: { 'Content-Range': `bytes */${fileSize}` }
            })
          }

          // 创建部分文件流
          const readStream = filePath.endsWith('.rpa')
            ? fs.createReadStream(filePath, {
              start: range.start,
              end: range.end,
              highWaterMark: 4 * 1024 * 1024 // 4MB 分块
            }).pipe(new DecryptTransform())
            : fs.createReadStream(filePath, {
              start: range.start,
              end: range.end,
              highWaterMark: 4 * 1024 * 1024 // 4MB 分块
            })

          // 构建响应头
          const headers = new Headers({
            'Content-Type': mime,
            'Content-Length': String(range.end - range.start + 1),
            'Content-Range': `bytes ${range.start}-${range.end}/${fileSize}`,
            'Accept-Ranges': 'bytes'
          })

          return new Response(readStream as unknown as ReadableStream<Uint8Array>, {
            status: 206,
            headers
          })
        } else {

          // 完整文件请求
          const readStream = filePath.endsWith('.rpa')
            ? fs.createReadStream(filePath).pipe(new DecryptTransform())
            : fs.createReadStream(filePath)

          const headers = new Headers({
            'Content-Type': mime,
            'Content-Length': String(fileSize)
          })

          return new Response(readStream as unknown as ReadableStream<Uint8Array>, {
            status: 200,
            headers
          })
        }
      })

      // 解析 Range 请求头
      function parseRangeHeader(
        rangeHeader: string,
        fileSize: number
      ): { start: number; end: number } | null {
        const match = rangeHeader.match(/bytes=(\d+)-(\d*)/)
        if (!match) return null

        const start = parseInt(match[1], 10)
        const end = match[2] ? parseInt(match[2], 10) : fileSize - 1

        if (start >= fileSize || end >= fileSize) {
          return null
        }

        return { start, end }
      }
    })

    app.on('window-all-closed', () => {
      if (process.platform !== 'darwin') {
        app.quit()
      }
    })

    // For macOS open file
    app.on('open-file', (e, path) => {
      // log.info('open-file:' + path)
      e.preventDefault()
      macOpenVideoURI = path
      if (mainWindow) {
        mainWindow.show()
      } else {
        createWindow()
      }
    })
  }
}

let macOpenVideoURI = ''

function resolveOpenedPathFromArgs(argv?: string[]): string {
  if (platform.isMacOS) {
    const uri = macOpenVideoURI
    macOpenVideoURI = ''
    return uri
  }
  const args = argv || process.argv
  const uri = args.find((arg) => arg.startsWith('--uri='))
  if (uri) {
    return uri.substring(6)
  }

  return args.pop() || ''
}

function playVideo(args?: string[]): void {
  const filePath = resolveOpenedPathFromArgs(args)

  if (filePath) {
    const video = getVideoFromPath(path.resolve(filePath))

    if (video) {
      sendIPC(IpcEvents.EV_PLAY, [video])
    }
  }
}

// 获取常见视频格式的 MIME 类型
function getMimeType(ext: string): string {
  const mimeTypes = {
    // 视频
    mp4: 'video/mp4',
    webm: 'video/webm',
    ogv: 'video/ogg',
    rpa: 'video/mp4',
    // 图片
    png: 'image/png',
    jpg: 'image/jpeg',
    jpeg: 'image/jpeg',
    gif: 'image/gif',
    webp: 'image/webp'
  }
  return mimeTypes[ext]
}

initApp()
